# TriggerSwitchD, executes commands to activate/deactive remote switches.
# (c) Copyright 2010 Pontus Strömdahl, AdhocSkill. 
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
require "serialport"

module TriggerSwitchD
  module ConfigFactory
    
    #Verifies proper path to environment.rb
    class ProperEnvironmentFile
      def initialize
        @paths_to_look = %w{~/.trigger_switch_d/config/ /etc/trigger_switch_d/config/ config/}
        @paths_to_look[0].gsub!("~",File.expand_path("~"))
        @env_name = "environment.rb"
      end
      
      def path
        env_path = @paths_to_look.find do |path|
          File.exist?("#{path}#{@env_name}")
        end
        return offer_to_create if env_path == nil
        "#{env_path}#{@env_name}"
      end
      
      private
      def offer_to_create
        return "" if ask == false
        create
        "#{@paths_to_look[0]}#{@env_name}"
      end
      
      def create
        home_path = @paths_to_look[0]
        Kernel.system("mkdir -p #{home_path}")
        Kernel.system("cp samples/environment.rb #{home_path}#{@env_name}")
      end
      
      def ask
          question = <<-EOS
        Could't find the environment.rb file. I would like to create one for you at
        #{@paths_to_look[0]} , do you want me to do that now [Yn]?
          EOS
          STDOUT.puts question
          (STDIN.gets =~ /[nN]/) == nil
      end
      
    end
    
    #Creates the Config class from the config/config.rb file
    #See samples/config.rb for more documentation
    def self.new(file=StringIO.new)
      env = file.readlines
      attributes = map_attributes(env)
      eval_config_code_definition(attributes)
      setup_environment(env)
    end
    
    private
    def self.map_attributes(env_list)
      env_list.map do |attribute|
        attribute.scan(/Config.([\w_]+) =/).flatten[0]
      end.compact
    end
    
    def self.setup_environment(env)
      env.map do |attribute|
        ::TriggerSwitchD.module_eval(attribute)
      end
      def Config.environment
        result = default_environment
        File.open(Config.dsl_path,"r") do |file|
          result[:lookup] = YAML::load(file)
        end
        result[:at_location] = Config.geo_position
        result
      end
    end

    def self.set_type(name)
      types = {"log_object" => "Hash.new(STDOUT).merge({:spec => StringIO.new, :development => STDOUT, 
                              :file => File.open(log_path,\"a+\")})",
                "output" => "Hash.new(STDOUT).merge({:spec => StringIO.new, :development => STDOUT, 
                              :vcp => Tellstick::ProxyIO.new(SerialPort,Config.vcp_port,4800,Proc.new { |sp| sp.puts(\"~^M~AT S7=45 S0=0 L1 V1 X4 &c1 E1 Q0^M\"); sp.puts(\"S+\"); sp.gets })})"}
      return "@#{name}=value" unless types.keys.include? name
      "@#{name}=#{types[name]}[value]"#.gsub("log_path","{log_path")
    end

    PATH_FILENAMES = {"log_path" => ["tsd.log"], "db_path" => ["devices","scheduled_actions"],
                 "dsl_path" => ["lookup.dsl"], "unix_socket_path" => ["com.adhocskill.trigger_switch_d"]}

    def self.append_filenames(name)
      return set_type(name) unless PATH_FILENAMES.keys.include? name
      filename = PATH_FILENAMES[name]
      result = filename.map do |fname|
        "#value}/#{fname}"
      end.inspect.gsub("value}","value.gsub(\"~\",File.expand_path(\"~\"))}").gsub("value","{value")
      result = result.gsub("[","").gsub("]","") if filename.length == 1
      "@#{name}=#{result}"
    end
    
    def self.eval_config_code_definition(attributes)
      cls = <<-EOS
      class Config
         #{attributes.map {|name| "def self.#{name}=(value); #{append_filenames(name)}; end; ; def self.#{name}; @#{name}; end "}.join("\n")}
         
         def self.default_environment
           {:lookup => {"tänd" => "activate", 
                     "släck" => "deactivate", 
                     "soluppgång" => "sunrise", 
                     "solnedgång" => "sunset",
                     "klockan" => "at",
                     "vid" => "at"},
           :at_location => {:north => 0.0, :west => 0.0}}
         end
         
         def self.flush_log
           log_object.flush
         end
      end
      EOS
      ::TriggerSwitchD.module_eval(cls)
    end
  end
end

